/*--------------------------------------------------------------------------
 *  Copyright 2011 Taro L. Saito
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *--------------------------------------------------------------------------*/
//--------------------------------------
// XerialJ
//
// SilkLensCompiler.java
// Since: 2011/06/22 22:09:50
//
// $URL$
// $Author$
//--------------------------------------
package org.xerial.silk.writer;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtNewMethod;
import javassist.NotFoundException;

import org.xerial.util.TypeInfo;
import org.xerial.util.lens.ObjectLens;
import org.xerial.util.lens.impl.ParameterGetter;

/**
 * 
 * @author leo
 * 
 */
public class SilkLensCompiler
{
    private HashMap<Class< ? >, SilkWeavable> silkPool = new HashMap<Class< ? >, SilkWeavable>();

    public String toSilk(Object obj) {
        StringBuilder buf = new StringBuilder();

        return buf.toString();
    }

    public <T> SilkWeavable createToSilk(Class<T> type) {

        try {
            ObjectLens lens = ObjectLens.getObjectLens(type);

            StringWriter javaCode = new StringWriter();
            PrintWriter c = new PrintWriter(javaCode);
            c.println("public void toSilk(Object obj, org.xerial.silk.writer.SilkWriter out) {");
            c.println(String.format("%s c = (%s) obj;", type.getName(), type.getName()));

            ClassPool classPool = ClassPool.getDefault();
            CtClass cl = classPool.makeClass(type.getCanonicalName() + ".Writer");
            cl.setInterfaces(new CtClass[] { classPool.get(SilkWeavable.class.getName()) });

            for (ParameterGetter eachGetter : lens.getGetterContainer()) {
                String paramName = eachGetter.toString();
                String naturalName = eachGetter.getNaturalParamName();

                Class< ? > paramType = eachGetter.getReturnType();
                if (paramType.isPrimitive()) {
                    c.println(String.format("out.leaf(\"%s\", c.%s);", naturalName, paramName));
                }
                else if (TypeInfo.isBasicType(paramType)) {
                    c.println(String.format("if(c.%s != null) {out.leaf(\"%s\", c.%s);}", paramName, naturalName,
                            paramName));
                }
                else {
                    c.println(String.format("if(c.%s != null) { out.leaf(\"%s\", c.%s); }", paramName, naturalName,
                            paramName));
                }
            }

            c.println("}");
            c.flush();
            cl.addMethod(CtNewMethod.make(javaCode.toString(), cl));

            return (SilkWeavable) cl.toClass().newInstance();
        }
        catch (CannotCompileException e) {
            e.printStackTrace();
        }
        catch (NotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;

    }
}
